package com.macro.mall.oms.service.order.impl;

import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.macro.mall.commission.entity.OrderPredicateEntity;
import com.macro.mall.commission.service.OrderPredicateService;
import com.macro.mall.common.api.exception.BusinessException;
import com.macro.mall.common.api.util.StringUtils;
import com.macro.mall.oms.domain.Order;
import com.macro.mall.oms.entity.OrderEntity;
import com.macro.mall.oms.mapper.OrderMapper;
import com.macro.mall.oms.service.order.OrderItemService;
import com.macro.mall.oms.service.order.OrderService;
import com.macro.mall.oms.service.order.bo.*;
import com.macro.mall.oms.util.OrderNoGenerateUtils;
import com.macro.mall.pay.service.wechat.WeChatPayService;
import com.macro.mall.pay.service.wechat.bo.WeChatRefundInput;
import com.macro.mall.pms.entity.ProductEntity;
import com.macro.mall.pms.entity.SkuEntity;
import com.macro.mall.pms.service.ProductService;
import com.macro.mall.pms.service.SkuService;
import com.macro.mall.ums.entity.MemberAddressEntity;
import com.macro.mall.ums.entity.MemberEntity;
import com.macro.mall.ums.enums.UserSourceTypeEnum;
import com.macro.mall.ums.service.account.MemberService;
import com.macro.mall.ums.service.address.MemberAddressService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 订单Service
 *
 * @author xuyanjun
 * @date 2019-12-10
 */
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private ProductService productService;

    @Autowired
    private SkuService skuService;

    @Autowired
    private MemberService memberService;

    @Autowired
    private MemberAddressService memberAddressService;

    @Autowired
    private OrderItemService orderItemService;

    @Autowired
    private WeChatPayService weChatPayService;

    @Autowired
    private OrderPredicateService orderPredicateService;

    /**
     * 取消订单
     *
     * @param orderId 订单id
     */
    @Override
    public void cancel(long orderId, String notifyUrl) {
        final OrderEntity orderEntity = getById(orderId);
        Assert.isTrue(orderEntity.getStatus() == 1, "只有处于[待发货]的订单才能取消。");

        WeChatRefundInput weChatRefundInput = new WeChatRefundInput();
        weChatRefundInput.setOrderId(orderId)
                .setSourceEnum(UserSourceTypeEnum.WX_MP)
                .setRefundAmount(orderEntity.getPayAmount())
                .setCallbackNotifyUrl(notifyUrl);

        UpdateOrderInput updateOrderInput = new UpdateOrderInput();
        updateOrderInput.setId(orderId);
        updateOrderInput.setStatus(4);

        update(updateOrderInput);

//        List<OrderPredicateEntity> orderPredicateEntities = orderPredicateService.listByOrderId(orderId);
//        orderPredicateEntities.forEach(x -> {
//            x.setCanceled(true);
//        });

      //  orderPredicateService.updateBatch(orderPredicateEntities);

        weChatPayService.refund(weChatRefundInput);
    }

    /**
     * 创建订单
     *
     * @param input input
     * @return 新增id
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public long create(CreateOrderInput input) {
        SkuEntity skuEntity = skuService.getById(input.getSkuId());
        Assert.isTrue(skuEntity.getStock() >= input.getQty(), "库存不足。");

        BigDecimal amount = skuEntity.getPrice().multiply(BigDecimal.valueOf(input.getQty()));

        MemberAddressEntity memberAddressEntity = memberAddressService.getById(input.getAddressId());
        MemberEntity memberEntity = memberService.getById(input.getMemberId());

        ProductEntity productEntity = productService.getById(skuEntity.getProductId());

        String orderNo = OrderNoGenerateUtils.nextNo();

        InsertOrderInput insertOrderInput = new InsertOrderInput();
        insertOrderInput.setMemberId(memberEntity.getId())
                .setMemberUsername(memberEntity.getUsername())
                .setOrderSn(orderNo)
                .setPayAmount(amount)
                .setTotalAmount(amount)
                .setReceiverProvince(memberAddressEntity.getProvince())
                .setReceiverCity(memberAddressEntity.getCity())
                .setReceiverRegion(memberAddressEntity.getRegion())
                .setReceiverDetailAddress(memberAddressEntity.getDetailAddress())
                .setReceiverName(memberAddressEntity.getName())
                .setReceiverPhone(memberAddressEntity.getPhoneNumber())
                .setReceiverPostCode(memberAddressEntity.getPostCode())
                .setNote(input.getRemark())
                .setCommission(productEntity.getCommission().multiply(new BigDecimal(input.getQty())));

        long orderId = insert(insertOrderInput);

        InsertOrderItemInput insertOrderItemInput = new InsertOrderItemInput();
        insertOrderItemInput.setMemberId(memberEntity.getId())
                .setOrderId(orderId)
                .setOrderSn(orderNo)
                .setProductId(productEntity.getId())
                .setProductName(productEntity.getName())
                .setProductPic(productEntity.getPic())
                .setProductPrice(productEntity.getPrice())
                .setRealAmount(amount)
                .setProductSkuId(skuEntity.getId())
                .setSp1(skuEntity.getSp1())
                .setSp2(skuEntity.getSp2())
                .setSp3(skuEntity.getSp3())
                .setProductQuantity(input.getQty());

        orderItemService.insert(insertOrderItemInput);

        return orderId;
    }

    /**
     * 新增订单
     *
     * @param input input
     * @return 新增id
     */
    private long insert(InsertOrderInput input) {
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setMemberId(input.getMemberId())
                .setOrderSn(input.getOrderSn())
                .setMemberUsername(input.getMemberUsername())
                .setTotalAmount(input.getTotalAmount())
                .setPayAmount(input.getPayAmount())
                .setFreightAmount(BigDecimal.ZERO)
                .setPromotionAmount(BigDecimal.ZERO)
                .setIntegrationAmount(BigDecimal.ZERO)
                .setCouponAmount(BigDecimal.ZERO)
                .setDiscountAmount(BigDecimal.ZERO)
                .setPayType(2)
                .setSourceType(1)
                .setStatus(0)
                .setOrderType(0)
                .setAutoConfirmDay(7)
                .setIntegration(0)
                .setGrowth(0)
                .setPromotionInfo(StringUtils.EMPTY)
                .setBillType(0)
                .setReceiverName(input.getReceiverName())
                .setReceiverPhone(input.getReceiverPhone())
                .setReceiverPostCode(input.getReceiverPostCode())
                .setReceiverProvince(input.getReceiverProvince())
                .setReceiverCity(input.getReceiverCity())
                .setReceiverRegion(input.getReceiverRegion())
                .setReceiverDetailAddress(input.getReceiverDetailAddress())
                .setDeleteStatus(0)
                .setUseIntegration(0)
                .setNote(input.getNote())
                .setCommission(input.getCommission());

        LocalDateTime now = LocalDateTime.now();
        orderEntity.setCreateTime(now);
        orderEntity.setModifyTime(now);

        orderMapper.insert(orderEntity);
        return orderEntity.getId();
    }

    /**
     * 修改订单
     *
     * @param input input
     */
    @Override
    public void update(UpdateOrderInput input) {
        OrderEntity orderEntity = orderMapper.selectById(input.getId());
        if (orderEntity == null) {
            throw new BusinessException(String.format("未能根据Id:%s找到指定的订单。", input.getId()));
        }

        orderEntity = new OrderEntity();
        orderEntity.setId(input.getId())
                .setFreightAmount(input.getFreightAmount())
                .setPromotionAmount(input.getPromotionAmount())
                .setIntegrationAmount(input.getIntegrationAmount())
                .setCouponAmount(input.getCouponAmount())
                .setDiscountAmount(input.getDiscountAmount())
                .setStatus(input.getStatus())
                .setDeliveryCompany(input.getDeliveryCompany())
                .setDeliverySn(input.getDeliverySn())
                .setAutoConfirmDay(input.getAutoConfirmDay())
                .setIntegration(input.getIntegration())
                .setGrowth(input.getGrowth())
                .setPromotionInfo(input.getPromotionInfo())
                .setBillType(input.getBillType())
                .setBillHeader(input.getBillHeader())
                .setBillContent(input.getBillContent())
                .setBillReceiverPhone(input.getBillReceiverPhone())
                .setBillReceiverEmail(input.getBillReceiverEmail())
                .setReceiverName(input.getReceiverName())
                .setReceiverPhone(input.getReceiverPhone())
                .setReceiverPostCode(input.getReceiverPostCode())
                .setReceiverProvince(input.getReceiverProvince())
                .setReceiverCity(input.getReceiverCity())
                .setReceiverRegion(input.getReceiverRegion())
                .setReceiverDetailAddress(input.getReceiverDetailAddress())
                .setNote(input.getNote())
                .setConfirmStatus(input.getConfirmStatus())
                .setUseIntegration(input.getUseIntegration())
                .setPaymentTime(input.getPaymentTime())
                .setDeliveryTime(input.getDeliveryTime())
                .setReceiveTime(input.getReceiveTime())
                .setCommentTime(input.getCommentTime())
                .setModifyTime(input.getModifyTime())
                .setCommission(input.getCommission())
                .setPredicateStatus(input.getPredicateStatus())
                .setPredicatePrice(input.getPredicatePrice())
                .setSettleStatus(input.getSettleStatus())
                .setSettlePrice(input.getSettlePrice())
                .setRefundTime(input.getRefundTime());

        orderEntity.setModifyTime(LocalDateTime.now());

        orderMapper.updateById(orderEntity);
    }

    /**
     * 修改订单预估状态
     *
     * @param id            id
     * @param predictStatus 预估状态
     */
    @Override
    public void updatePredictStatus(long id, int predictStatus) {
        Assert.isTrue(id > 0, "订单id不能为空。");

        orderMapper.updatePredictStatus(id, predictStatus);
    }

    /**
     * 修改订单结算状态
     *
     * @param id           id
     * @param settleStatus 结算状态
     */
    @Override
    public void updateSettleStatus(long id, int settleStatus) {
        Assert.isTrue(id > 0, "订单id不能为空。");

        orderMapper.updateSettleStatus(id, settleStatus);
    }

    /**
     * 删除订单
     *
     * @param id id
     */
    @Override
    public void delete(long id) {
        orderMapper.deleteById(id);
    }

    /**
     * 根据Id获取订单
     *
     * @param id id
     * @return 订单
     */
    @Override
    public OrderEntity getById(long id) {
        return orderMapper.selectById(id);
    }

    /**
     * 根据批量Id获取订单
     *
     * @param batchIds 批量ids
     * @return 订单集合
     */
    @Override
    public List<OrderEntity> listByBatchIds(List<Long> batchIds) {
        if (batchIds == null || batchIds.isEmpty()) {
            return new ArrayList<>();
        }
        return orderMapper.selectBatchIds(batchIds);
    }

    /**
     * 获取可预估订单
     *
     * @param paymentTimeBeginTime 完成开始时间
     * @param paymentTimeEndTime   完成结束时间
     * @return 可结算订单
     */
    @Override
    public List<OrderEntity> listPredictable(LocalDateTime paymentTimeBeginTime, LocalDateTime paymentTimeEndTime) {
        LambdaQueryWrapper<OrderEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.gt(OrderEntity::getPaymentTime, paymentTimeBeginTime);
        queryWrapper.le(OrderEntity::getPaymentTime, paymentTimeEndTime);
        queryWrapper.in(OrderEntity::getStatus, Arrays.asList(1, 2));
        queryWrapper.eq(OrderEntity::getPredicateStatus, 5);

        return orderMapper.selectList(queryWrapper);
    }

    /**
     * 获取可结算订单
     *
     * @param completedBeginTime 完成开始时间
     * @param completedEndTime   完成结束时间
     * @return 可结算订单
     */
    @Override
    public List<OrderEntity> listSettlable(LocalDateTime completedBeginTime, LocalDateTime completedEndTime) {
        LambdaQueryWrapper<OrderEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.gt(OrderEntity::getPaymentTime, completedBeginTime);
        queryWrapper.le(OrderEntity::getPaymentTime, completedEndTime);
        queryWrapper.in(OrderEntity::getStatus, Arrays.asList(1, 2));
        queryWrapper.eq(OrderEntity::getSettleStatus, 5);

        return orderMapper.selectList(queryWrapper);
    }

    /**
     * 分页查询
     *
     * @param input input
     * @return 分页的订单
     */
    @Override
    public Page<OrderEntity> pagedQuery(PagedQueryOrderInput input) {
        LambdaQueryWrapper<OrderEntity> queryWrapper = Wrappers.lambdaQuery();

        if (input.getMemberId() != null) {
            queryWrapper.eq(OrderEntity::getMemberId, input.getMemberId());
        }
        if (input.getStatus() != null) {
            queryWrapper.eq(OrderEntity::getStatus, input.getStatus());
        }
        if ("create_time".equals(input.getSortField())) {
            queryWrapper.orderBy(true, input.isAsc(), OrderEntity::getCreateTime);
        }

        PageHelper.startPage(input.getPageIndex(), input.getPageSize());

        return (Page<OrderEntity>) orderMapper.selectList(queryWrapper);
    }

    /**
     * 将实体对象转换成domain对象
     *
     * @param orderEntity 实体
     * @return order
     */
    @Override
    public Order entityToDomain(OrderEntity orderEntity) {
        if (orderEntity == null) {
            return null;
        }

        Order order = new Order();
        order.setId(orderEntity.getId())
                .setMemberId(orderEntity.getMemberId())
                .setCouponId(orderEntity.getCouponId())
                .setOrderSn(orderEntity.getOrderSn())
                .setCreateTime(orderEntity.getCreateTime())
                .setMemberUsername(orderEntity.getMemberUsername())
                .setTotalAmount(orderEntity.getTotalAmount())
                .setPayAmount(orderEntity.getPayAmount())
                .setFreightAmount(orderEntity.getFreightAmount())
                .setPromotionAmount(orderEntity.getPromotionAmount())
                .setIntegrationAmount(orderEntity.getIntegrationAmount())
                .setCouponAmount(orderEntity.getCouponAmount())
                .setDiscountAmount(orderEntity.getDiscountAmount())
                .setPayType(orderEntity.getPayType())
                .setSourceType(orderEntity.getSourceType())
                .setStatus(orderEntity.getStatus())
                .setOrderType(orderEntity.getOrderType())
                .setDeliveryCompany(orderEntity.getDeliveryCompany())
                .setDeliverySn(orderEntity.getDeliverySn())
                .setAutoConfirmDay(orderEntity.getAutoConfirmDay())
                .setIntegration(orderEntity.getIntegration())
                .setGrowth(orderEntity.getGrowth())
                .setPromotionInfo(orderEntity.getPromotionInfo())
                .setBillType(orderEntity.getBillType())
                .setBillHeader(orderEntity.getBillHeader())
                .setBillContent(orderEntity.getBillContent())
                .setBillReceiverPhone(orderEntity.getBillReceiverPhone())
                .setBillReceiverEmail(orderEntity.getBillReceiverEmail())
                .setReceiverName(orderEntity.getReceiverName())
                .setReceiverPhone(orderEntity.getReceiverPhone())
                .setReceiverPostCode(orderEntity.getReceiverPostCode())
                .setReceiverProvince(orderEntity.getReceiverProvince())
                .setReceiverCity(orderEntity.getReceiverCity())
                .setReceiverRegion(orderEntity.getReceiverRegion())
                .setReceiverDetailAddress(orderEntity.getReceiverDetailAddress())
                .setNote(orderEntity.getNote())
                .setConfirmStatus(orderEntity.getConfirmStatus())
                .setDeleteStatus(orderEntity.getDeleteStatus())
                .setUseIntegration(orderEntity.getUseIntegration())
                .setPaymentTime(orderEntity.getPaymentTime())
                .setDeliveryTime(orderEntity.getDeliveryTime())
                .setReceiveTime(orderEntity.getReceiveTime())
                .setCommentTime(orderEntity.getCommentTime())
                .setModifyTime(orderEntity.getModifyTime());

        return order;
    }

    /**
     * 将实体对象转换成domain对象
     *
     * @param orderEntities 实体
     * @return orders
     */
    @Override
    public List<Order> entityToDomain(List<OrderEntity> orderEntities) {
        List<Order> result = new ArrayList<>();
        if (orderEntities == null) {
            return result;
        }

        for (OrderEntity orderEntity : orderEntities) {
            Order order = entityToDomain(orderEntity);
            result.add(order);
        }
        return result;
    }

}
